package apobates.gui.formatter.storage;

import apobates.gui.formatter.packet.ResourceType;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;
import java.lang.reflect.Type;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 * 使用Json文件作为最近记录的执行器
 */
public final class JsonStorageRecentExecutor implements GeneralRecentExecutor {
    private final static String recentFILE = "yalla_resource_recent.json";
    private final File cachePath;
    private final static Type cacheRsType = new TypeToken<Set<RecentRecord>>() {}.getType();
    private final static JsonStorageRecentExecutor INSTANCE;
    // 在内容中保存@20230404
    private CopyOnWriteArraySet<RecentRecord> memorize;

    static {
        INSTANCE = new JsonStorageRecentExecutor();
    }

    private JsonStorageRecentExecutor(File cachePath) {
        this.cachePath = cachePath;
        this.memorize = new CopyOnWriteArraySet<>();
    }

    private JsonStorageRecentExecutor() {
        this(new File(System.getProperty("java.io.tmpdir"), recentFILE));
    }

    /**
     * 返回最近记录的执行器
     * @return
     */
    public static JsonStorageRecentExecutor getInstance(){
        return INSTANCE;
    }
    /**
     * 所有最近请求记录
     * @return 读取失败返回空列表
     */
    @Override
    public Set<RecentRecord> getAll() {
        if(null != memorize && !memorize.isEmpty()){
            return memorize;
        }
        try {
            try (FileReader fileReader = new FileReader(cachePath);
                 JsonReader jsonWriter = new JsonReader(fileReader)) {
                Gson gson = new GsonBuilder().create();
                Set<RecentRecord> rs = gson.fromJson(jsonWriter, cacheRsType);
                // 放入内存中@20230404
                memorize.addAll(rs);
                return rs;
            }
        }catch (IOException e){
            return Collections.emptySet();
        }
    }

    /**
     * 查看指定资源类型最近的所有请求记录
     * @param type Json资源类型
     * @return
     */
    @Override
    public Set<RecentRecord> getType(ResourceType type){
        return getAll().stream().filter(ele->ele.getType().equals(type)).collect(Collectors.toSet());
    }

    /**
     * 查看指定资源类型最近的一条请求记录
     * @param type Json资源类型
     * @return
     */
    @Override
    public Optional<RecentRecord> getLastByType(ResourceType type){
        return getAll()
                .stream()
                .filter(ele->ele.getType().equals(type))
                .sorted(Comparator.comparing(RecentRecord::getDateTime).reversed())
                .findFirst();
    }
    /**
     * 是否存在最近记录
     * @return true存在
     */
    @Override
    public boolean isExists(){
        File file = new File(System.getProperty("java.io.tmpdir"), recentFILE);
        return file.exists();
    }
    // 创建文件
    private void create(Collection<RecentRecord> recordes){
        try(FileWriter fileWriter = new FileWriter(cachePath)) {
            Gson gson = new GsonBuilder().create();
            gson.toJson(recordes, cacheRsType, fileWriter);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 添加最近记录
    private int append(RecentRecord record){
        Set<RecentRecord> rs = getAll();
        if(null == rs) {
            rs = Set.of(record);
        }else{
            rs.add(record);
        }
        try(FileWriter fileWriter = new FileWriter(cachePath)) {
            Gson gson = new GsonBuilder().create();
            gson.toJson(rs, cacheRsType, fileWriter);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return rs.size();
    }

    /**
     * 不存在最近记录创建.若已经存在则追加记录
     * @param record 最近资源访问记录
     * @return 返回目前最近记录的数量
     */
    @Override
    public int replace(RecentRecord record){
        /*
        // 同步
        if(!isExists()){
            create(record);
            return 1;
        }
        return append(record);*/
        // 异步
        return this.replaceAsync(record);
    }

    @Override
    public boolean delete(ResourceType type, String path) {
        int affect = -1;
        Iterator<RecentRecord> iterator = memorize.iterator();
        while(iterator.hasNext()){
            RecentRecord rr = iterator.next();
            if(rr.getPath().equals(path) && rr.getType() == type){
                if(memorize.remove(rr)) {
                    affect = 1;
                }
                break;
            }
        }
        return affect == 1 ? true : false;
    }

    private int replaceAsync(RecentRecord record){
        Optional<RecentRecord> existOne = getOne(record.getType(), record.getPath());
        if(existOne.isPresent()){
            // 更新日期
            existOne.get().setDateTime(LocalDateTime.now());
        } else {
            memorize.add(record);
        }
        return memorize.size();
    }
    private Optional<RecentRecord> getOne(ResourceType type, String path){
        return memorize.stream().filter(ele->ele.getType() == type && ele.getPath().equals(path)).findAny();
    }
    @Override
    public void persiste(){
        System.out.println("[JSRE] start persiste");
        this.create(memorize);
    }
}
